home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch17 / Checker.cls < prev    next >
Text File  |  1999-07-06  |  17KB  |  528 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "RayCheckerboard"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = False
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16. ' A checkerboard in a plane.
  17.  
  18. Implements RayTraceable
  19.  
  20. Private Point1 As Point3D       ' Point on corner.
  21. Private Point2 As Point3D       ' Point on 1st corner of first rectangle.
  22. Private Point3 As Point3D       ' Point on 2nd corner of first rectangle.
  23. Private NumSquares1 As Integer  ' # squares in 1st direction.
  24. Private NumSquares2 As Integer  ' # squares in 2nd direction.
  25.  
  26. ' Ambient light parameters.
  27. Private AmbientKr As Single
  28. Private AmbientKg As Single
  29. Private AmbientKb As Single
  30.  
  31. ' Diffuse light parameters.
  32. Private DiffuseKr As Single
  33. Private DiffuseKg As Single
  34. Private DiffuseKb As Single
  35.  
  36. ' Specular reflection parameters.
  37. Private SpecularN As Single
  38. Private SpecularK As Single
  39.  
  40. ' Reflected light parameters.
  41. Private ReflectedKr As Single
  42. Private ReflectedKg As Single
  43. Private ReflectedKb As Single
  44.  
  45. ' Refracted light parameters.
  46. Private TransN As Single
  47. Private n1 As Single   ' Index of refraction outside the object.
  48. Private n2 As Single   ' Index of refraction inside the object.
  49. Private TransmittedKr As Single
  50. Private TransmittedKg As Single
  51. Private TransmittedKb As Single
  52.  
  53. Private IsReflective As Boolean
  54. Private IsTransparent As Boolean
  55. Private DoneOnThisScanline As Boolean
  56.  
  57. ' We had a hit on this scanline.
  58. Private HadHit As Boolean
  59.  
  60. ' We have had a hit on a previous scanline.
  61. Private HadHitOnPreviousScanline As Boolean
  62.  
  63. ' We will not be visible on later scanlines.
  64. Private ForeverCulled As Boolean
  65. ' Return an appropriate color for this object.
  66. Private Function GetColor() As Long
  67. Dim R As Integer
  68. Dim G As Integer
  69. Dim B As Integer
  70.  
  71.     R = 255 * (DiffuseKr + AmbientKr): If R > 255 Then R = 255
  72.     G = 255 * (DiffuseKg + AmbientKg): If G > 255 Then G = 255
  73.     B = 255 * (DiffuseKb + AmbientKb): If B > 255 Then B = 255
  74.     GetColor = RGB(R, G, B)
  75. End Function
  76. ' Return the right shade for this polygon.
  77. Private Function GetShade(ByVal pgon As SimplePolygon) As Long
  78. Dim i As Integer
  79. Dim px As Single
  80. Dim py As Single
  81. Dim pz As Single
  82. Dim light_source As LightSource
  83. Dim total_r As Single
  84. Dim total_g As Single
  85. Dim total_b As Single
  86. Dim R1 As Integer
  87. Dim g1 As Integer
  88. Dim b1 As Integer
  89. Dim empty_objects As Collection
  90.  
  91.     With pgon
  92.         ' Find a central point on this polygon.
  93.         For i = 1 To .PointX.Count
  94.             px = px + .PointX(i)
  95.             py = py + .PointY(i)
  96.             pz = pz + .PointZ(i)
  97.         Next i
  98.         px = px / .PointX.Count
  99.         py = py / .PointX.Count
  100.         pz = pz / .PointX.Count
  101.  
  102.         ' Add up the light components.
  103.         Set empty_objects = New Collection
  104.         For Each light_source In LightSources
  105.             CalculateHitColorDSA _
  106.                 1, empty_objects, Nothing, _
  107.                 EyeX, EyeY, EyeZ, _
  108.                 px, py, pz, .Nx, .Ny, .Nz, _
  109.                 DiffuseKr, DiffuseKg, DiffuseKb, AmbientKr, AmbientKg, AmbientKb, _
  110.                 SpecularK, SpecularN, R1, g1, b1
  111.             total_r = total_r + R1
  112.             total_g = total_g + g1
  113.             total_b = total_b + b1
  114.         Next light_source
  115.     End With
  116.  
  117.     If total_r > 255 Then total_r = 255
  118.     If total_g > 255 Then total_g = 255
  119.     If total_b > 255 Then total_b = 255
  120.  
  121.     GetShade = RGB(total_r, total_g, total_b)
  122. End Function
  123.  
  124. ' Return the unit surface normal.
  125. Private Sub GetUnitNormal(ByRef Nx As Single, ByRef Ny As Single, ByRef Nz As Single)
  126. Dim v1x As Single
  127. Dim v1y As Single
  128. Dim v1z As Single
  129. Dim v2x As Single
  130. Dim v2y As Single
  131. Dim v2z As Single
  132. Dim n_len As Single
  133.  
  134.     ' Get the square vectors.
  135.     v1x = Point2.Trans(1) - Point1.Trans(1)
  136.     v1y = Point2.Trans(2) - Point1.Trans(2)
  137.     v1z = Point2.Trans(3) - Point1.Trans(3)
  138.     v2x = Point3.Trans(1) - Point1.Trans(1)
  139.     v2y = Point3.Trans(2) - Point1.Trans(2)
  140.     v2z = Point3.Trans(3) - Point1.Trans(3)
  141.  
  142.     ' Calculate the normal.
  143.     m3Cross Nx, Ny, Nz, v1x, v1y, v1z, v2x, v2y, v2z
  144.     n_len = Sqr(Nx * Nx + Ny * Ny + Nz * Nz)
  145.     Nx = Nx / n_len
  146.     Ny = Ny / n_len
  147.     Nz = Nz / n_len
  148. End Sub
  149. ' Add non-backface polygons to this collection.
  150. Public Sub RayTraceable_GetPolygons(ByRef num_polygons As Integer, polygons() As SimplePolygon, ByVal shaded As Boolean)
  151. Dim pgon As SimplePolygon
  152. Dim px As Single
  153. Dim py As Single
  154. Dim pz As Single
  155. Dim v1x As Single
  156. Dim v1y As Single
  157. Dim v1z As Single
  158. Dim v2x As Single
  159. Dim v2y As Single
  160. Dim v2z As Single
  161. Dim i As Integer
  162. Dim j As Integer
  163.  
  164.     ' Get the square vectors.
  165.     px = Point1.Trans(1)
  166.     py = Point1.Trans(2)
  167.     pz = Point1.Trans(3)
  168.     v1x = Point2.Trans(1) - px
  169.     v1y = Point2.Trans(2) - py
  170.     v1z = Point2.Trans(3) - pz
  171.     v2x = Point3.Trans(1) - px
  172.     v2y = Point3.Trans(2) - py
  173.     v2z = Point3.Trans(3) - pz
  174.  
  175.     ' Make the squares.
  176.     For i = 0 To NumSquares1 - 1
  177.         For j = 0 To NumSquares2 - 1
  178.             If (i + j) Mod 2 = 0 Then
  179.                 ' Make a polygon.
  180.                 Set pgon = New SimplePolygon
  181.                 pgon.AddPoint px + i * v1x + j * v2x, py + i * v1y + j * v2y, pz + i * v1z + j * v2z
  182.                 pgon.AddPoint px + (i + 1) * v1x + j * v2x, py + (i + 1) * v1y + j * v2y, pz + (i + 1) * v1z + j * v2z
  183.                 pgon.AddPoint px + (i + 1) * v1x + (j + 1) * v2x, py + (i + 1) * v1y + (j + 1) * v2y, pz + (i + 1) * v1z + (j + 1) * v2z
  184.                 pgon.AddPoint px + i * v1x + (j + 1) * v2x, py + i * v1y + (j + 1) * v2y, pz + i * v1z + (j + 1) * v2z
  185.  
  186.                 ' See if we are shaded.
  187.                 If shaded Then
  188.                     ' We are shaded. Get the right color.
  189.                     pgon.ForeColor = GetShade(pgon)
  190.                     pgon.FillColor = pgon.ForeColor
  191.                 Else
  192.                     ' We are not shaded. Use the normal colors.
  193.                     pgon.ForeColor = vbBlack
  194.                     pgon.FillColor = GetColor()
  195.                 End If
  196.  
  197.                 ' Add the polygon to the list.
  198.                 num_polygons = num_polygons + 1
  199.                 ReDim Preserve polygons(1 To num_polygons)
  200.                 Set polygons(num_polygons) = pgon
  201.             End If
  202.         Next j
  203.     Next i
  204. End Sub
  205. ' Draw a wireframe for this object.
  206. Public Sub RayTraceable_DrawWireFrame(ByVal pic As PictureBox)
  207. Dim px As Single
  208. Dim py As Single
  209. Dim v1x As Single
  210. Dim v1y As Single
  211. Dim v2x As Single
  212. Dim v2y As Single
  213. Dim i As Integer
  214. Dim j As Integer
  215.  
  216.     ' Use an appropriate color.
  217.     pic.ForeColor = GetColor()
  218.  
  219.     ' Get the square vectors.
  220.     px = Point1.Trans(1)
  221.     py = Point1.Trans(2)
  222.     v1x = Point2.Trans(1) - px
  223.     v1y = Point2.Trans(2) - py
  224.     v2x = Point3.Trans(1) - px
  225.     v2y = Point3.Trans(2) - py
  226.  
  227.     ' Draw the squares.
  228.     For i = 0 To NumSquares1 - 1
  229.         For j = 0 To NumSquares2 - 1
  230.             If (i + j) Mod 2 = 0 Then
  231.                 pic.Line (px + i * v1x + j * v2x, py + i * v1y + j * v2y)-(px + (i + 1) * v1x + j * v2x, py + (i + 1) * v1y + j * v2y)
  232.                 pic.Line -(px + (i + 1) * v1x + (j + 1) * v2x, py + (i + 1) * v1y + (j + 1) * v2y)
  233.                 pic.Line -(px + i * v1x + (j + 1) * v2x, py + i * v1y + (j + 1) * v2y)
  234.                 pic.Line -(px + i * v1x + j * v2x, py + i * v1y + j * v2y)
  235.             End If
  236.         Next j
  237.     Next i
  238. End Sub
  239.  
  240. ' Initialize the object using text parameters in
  241. ' a comma-delimited list.
  242. Public Sub SetParameters(ByVal txt As String)
  243.     On Error GoTo CheckerboardParamError
  244.  
  245.     ' Read the parameters and initialize the object.
  246.     ' Geometry.
  247.     NumSquares1 = CInt(GetDelimitedToken(txt, ","))
  248.     NumSquares2 = CInt(GetDelimitedToken(txt, ","))
  249.     Point1.Coord(1) = CSng(GetDelimitedToken(txt, ","))
  250.     Point1.Coord(2) = CSng(GetDelimitedToken(txt, ","))
  251.     Point1.Coord(3) = CSng(GetDelimitedToken(txt, ","))
  252.     Point1.Coord(4) = 1
  253.     Point2.Coord(1) = CSng(GetDelimitedToken(txt, ","))
  254.     Point2.Coord(2) = CSng(GetDelimitedToken(txt, ","))
  255.     Point2.Coord(3) = CSng(GetDelimitedToken(txt, ","))
  256.     Point2.Coord(4) = 1
  257.     Point3.Coord(1) = CSng(GetDelimitedToken(txt, ","))
  258.     Point3.Coord(2) = CSng(GetDelimitedToken(txt, ","))
  259.     Point3.Coord(3) = CSng(GetDelimitedToken(txt, ","))
  260.     Point3.Coord(4) = 1
  261.  
  262.     ' Ambient light.
  263.     AmbientKr = CSng(GetDelimitedToken(txt, ","))
  264.     AmbientKg = CSng(GetDelimitedToken(txt, ","))
  265.     AmbientKb = CSng(GetDelimitedToken(txt, ","))
  266.  
  267.     ' Diffuse reflection.
  268.     DiffuseKr = CSng(GetDelimitedToken(txt, ","))
  269.     DiffuseKg = CSng(GetDelimitedToken(txt, ","))
  270.     DiffuseKb = CSng(GetDelimitedToken(txt, ","))
  271.  
  272.     ' Specular reflection.
  273.     SpecularN = CSng(GetDelimitedToken(txt, ","))
  274.     SpecularK = CSng(GetDelimitedToken(txt, ","))
  275.  
  276.     ' Reflected light.
  277.     ReflectedKr = CSng(GetDelimitedToken(txt, ","))
  278.     ReflectedKg = CSng(GetDelimitedToken(txt, ","))
  279.     ReflectedKb = CSng(GetDelimitedToken(txt, ","))
  280.     IsReflective = (ReflectedKr > 0) Or (ReflectedKg > 0) Or (ReflectedKb > 0)
  281.  
  282.     ' Transmitted light.
  283.     TransN = CSng(GetDelimitedToken(txt, ","))
  284.     n1 = CSng(GetDelimitedToken(txt, ","))
  285.     n2 = CSng(GetDelimitedToken(txt, ","))
  286.     TransmittedKr = CSng(GetDelimitedToken(txt, ","))
  287.     TransmittedKg = CSng(GetDelimitedToken(txt, ","))
  288.     TransmittedKb = CSng(GetDelimitedToken(txt, ","))
  289.     IsTransparent = (TransmittedKr > 0) Or (TransmittedKg > 0) Or (TransmittedKb > 0)
  290.  
  291.     Exit Sub
  292.  
  293. CheckerboardParamError:
  294.     MsgBox "Error initializing checkerboard parameters."
  295. End Sub
  296.  
  297. ' Apply a transformation matrix to the object.
  298. Public Sub RayTraceable_Apply(M() As Single)
  299.     ' Transform the points.
  300.     m3Apply Point1.Coord, M, Point1.Trans
  301.     m3Apply Point2.Coord, M, Point2.Trans
  302.     m3Apply Point3.Coord, M, Point3.Trans
  303. End Sub
  304. ' Apply a transformation matrix to the object.
  305. Public Sub RayTraceable_ApplyFull(M() As Single)
  306.     ' Transform the points.
  307.     m3ApplyFull Point1.Coord, M, Point1.Trans
  308.     m3ApplyFull Point2.Coord, M, Point2.Trans
  309.     m3ApplyFull Point3.Coord, M, Point3.Trans
  310. End Sub
  311.  
  312. ' Draw the object with backfaces removed.
  313. ' Draw the whole wire frame for planes.
  314. Public Sub RayTraceable_DrawBackfacesRemoved(ByVal pic As PictureBox)
  315.     RayTraceable_DrawWireFrame pic
  316. End Sub
  317. ' Return the red, green, and blue components of
  318. ' the surface at the hit position.
  319. Public Sub RayTraceable_FindHitColor(ByVal depth As Integer, Objects As Collection, ByVal eye_x As Single, ByVal eye_y As Single, ByVal eye_z As Single, ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByRef R As Integer, ByRef G As Integer, ByRef B As Integer)
  320. Dim Nx As Single
  321. Dim Ny As Single
  322. Dim Nz As Single
  323. Dim Vx As Single
  324. Dim Vy As Single
  325. Dim Vz As Single
  326. Dim NdotV As Single
  327.  
  328.     ' Find the unit normal at this point.
  329.     GetUnitNormal Nx, Ny, Nz
  330.  
  331.     ' Make sure the normal points towards the
  332.     ' center of projection.
  333.     Vx = EyeX - px
  334.     Vy = EyeY - py
  335.     Vz = EyeZ - pz
  336.     NdotV = Nx * Vx + Ny * Vy + Nz * Vz
  337.     If NdotV < 0 Then
  338.         Nx = -Nx
  339.         Ny = -Ny
  340.         Nz = -Nz
  341.     End If
  342.  
  343.     ' Get the hit color.
  344.     CalculateHitColor depth, Objects, Me, _
  345.         eye_x, eye_y, eye_z, _
  346.         px, py, pz, _
  347.         Nx, Ny, Nz, _
  348.         DiffuseKr, DiffuseKg, DiffuseKb, _
  349.         AmbientKr, AmbientKg, AmbientKb, _
  350.         SpecularK, SpecularN, _
  351.         ReflectedKr, ReflectedKg, ReflectedKb, IsReflective, _
  352.         TransmittedKr, TransmittedKg, TransmittedKb, TransN, n1, n2, IsTransparent, _
  353.         R, G, B
  354. End Sub
  355. ' See if the scanline plane with the indicated
  356. ' point and normal intersects this object.
  357. Public Sub RayTraceable_CullScanline(ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByVal Nx As Single, ByVal Ny As Single, ByVal Nz As Single)
  358.     ' Do not scanline cull.
  359.     DoneOnThisScanline = False
  360. End Sub
  361. ' Return the value T for the point of intersection
  362. ' between the vector from point (px, py, pz) in
  363. ' the direction <vx, vy, vz>.
  364. '
  365. ' direct_calculation is true if we are finding the
  366. ' intersection from a viewing position ray. It is
  367. ' false if we are finding an reflected intersection
  368. ' or a shadow feeler.
  369. Public Function RayTraceable_FindT(ByVal direct_calculation As Boolean, ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByVal Vx As Single, ByVal Vy As Single, ByVal Vz As Single) As Single
  370. Dim A As Single
  371. Dim B As Single
  372. Dim C As Single
  373. Dim D As Single
  374. Dim Nx As Single
  375. Dim Ny As Single
  376. Dim Nz As Single
  377. Dim denom As Single
  378. Dim t As Single
  379. Dim Cx As Single
  380. Dim Cy As Single
  381. Dim Cz As Single
  382. Dim dx As Single
  383. Dim dy As Single
  384. Dim dz As Single
  385. Dim X As Single
  386. Dim Y As Single
  387. Dim Z As Single
  388. Dim v1x As Single
  389. Dim v1y As Single
  390. Dim v1z As Single
  391. Dim v2x As Single
  392. Dim v2y As Single
  393. Dim v2z As Single
  394. Dim i As Single
  395. Dim j As Single
  396.  
  397.     ' See if we have been culled.
  398.     If direct_calculation And DoneOnThisScanline Then
  399.         RayTraceable_FindT = -1
  400.         Exit Function
  401.     End If
  402.  
  403.     ' Find the unit normal at this point.
  404.     GetUnitNormal Nx, Ny, Nz
  405.  
  406.     ' Compute the plane's parameters.
  407.     A = Nx
  408.     B = Ny
  409.     C = Nz
  410.     D = -(Nx * Point1.Trans(1) + _
  411.           Ny * Point1.Trans(2) + _
  412.           Nz * Point1.Trans(3))
  413.  
  414.     ' If the denominator = 0, the ray is parallel
  415.     ' to the plane so there's no intersection.
  416.     denom = A * Vx + B * Vy + C * Vz
  417.     If denom = 0 Then
  418.         RayTraceable_FindT = -1
  419.         Exit Function
  420.     End If
  421.  
  422.     ' Solve for t.
  423.     t = -(A * px + B * py + C * pz + D) / denom
  424.  
  425.     ' If there is no positive t value, there's no
  426.     ' intersection in this direction.
  427.     If t < 0.01 Then
  428.         RayTraceable_FindT = -1
  429.         Exit Function
  430.     End If
  431.  
  432.     ' Get the point of intersection with the plane.
  433.     X = px + t * Vx
  434.     Y = py + t * Vy
  435.     Z = pz + t * Vz
  436.  
  437.     ' Get the square vectors.
  438.     px = Point1.Trans(1)
  439.     py = Point1.Trans(2)
  440.     pz = Point1.Trans(3)
  441.     v1x = Point2.Trans(1) - px
  442.     v1y = Point2.Trans(2) - py
  443.     v1z = Point2.Trans(3) - pz
  444.     v2x = Point3.Trans(1) - px
  445.     v2y = Point3.Trans(2) - py
  446.     v2z = Point3.Trans(3) - pz
  447.  
  448.     ' Get the i and j values for this point.
  449.     If (Abs(v1x) > 0.001) And (Abs(v1y * v2x - v2y * v1x) > 0.001) Then
  450.         j = (v1y * (X - px) + v1x * (py - Y)) / (v1y * v2x - v2y * v1x)
  451.         i = (X - px - v2x * j) / v1x
  452.     ElseIf (Abs(v1y) > 0.001) And (Abs(v1z * v2y - v2z * v1y) > 0.001) Then
  453.         j = (v1z * (Y - py) + v1y * (pz - Z)) / (v1z * v2y - v2z * v1y)
  454.         i = (Y - py - v2y * j) / v1y
  455.     Else
  456.         j = (v1x * (Z - pz) + v1z * (px - X)) / (v1x * v2z - v2x * v1z)
  457.         i = (Z - pz - v2z * j) / v1z
  458.     End If
  459.  
  460.     ' See if the point is ok.
  461.     If (i < 0) Or (j < 0) Or (i > NumSquares1) Or (j > NumSquares2) Then
  462.         ' Not on the area of interest.
  463.         RayTraceable_FindT = -1
  464.         Exit Function
  465.     ElseIf (Int(i) + Int(j)) Mod 2 <> 0 Then
  466.         ' Not on a drawn square.
  467.         RayTraceable_FindT = -1
  468.         Exit Function
  469.     Else
  470.         ' We had a hit.
  471.         If direct_calculation Then HadHit = True
  472.  
  473.         RayTraceable_FindT = t
  474.     End If
  475. End Function
  476. ' Return the minimum and maximum distances from
  477. ' this point.
  478. ' Use the wireframe points.
  479. Private Sub RayTraceable_GetRminRmax(new_min As Single, new_max As Single, ByVal X As Single, ByVal Y As Single, ByVal Z As Single)
  480. Dim dx As Single
  481. Dim dy As Single
  482. Dim dz As Single
  483. Dim px As Single
  484. Dim py As Single
  485. Dim pz As Single
  486. Dim v1x As Single
  487. Dim v1y As Single
  488. Dim v1z As Single
  489. Dim v2x As Single
  490. Dim v2y As Single
  491. Dim v2z As Single
  492. Dim i As Integer
  493. Dim j As Integer
  494. Dim dist As Single
  495.  
  496.     new_min = 1E+30
  497.     new_max = -1E+30
  498.  
  499.     ' Get the square vectors.
  500.     px = Point1.Trans(1)
  501.     py = Point1.Trans(2)
  502.     pz = Point1.Trans(3)
  503.     v1x = Point2.Trans(1) - px
  504.     v1y = Point2.Trans(2) - py
  505.     v1z = Point2.Trans(3) - pz
  506.     v2x = Point3.Trans(1) - px
  507.     v2y = Point3.Trans(2) - py
  508.     v2z = Point3.Trans(3) - pz
  509.  
  510.     For i = 0 To NumSquares1 Step NumSquares1
  511.         For j = 0 To NumSquares2 Step NumSquares2
  512.             dx = X - (px + i * v1x + j * v2x)
  513.             dy = Y - (py + i * v1y + j * v2y)
  514.             dz = Z - (pz + i * v1z + j * v2z)
  515.             dist = Sqr(dx * dx + dy * dy + dz * dz)
  516.             If new_min > dist Then new_min = dist
  517.             If new_max < dist Then new_max = dist
  518.         Next j
  519.     Next i
  520. End Sub
  521. ' Reset the ForeverCulled flag.
  522. Private Sub RayTraceable_ResetCulling()
  523.     ForeverCulled = False
  524.     HadHitOnPreviousScanline = False
  525. End Sub
  526.  
  527.  
  528.